<template>
  <div class="basic_map_wrapper">
    <div v-if="breadInfo.length !== 1" class="bread">
      <span
        v-for="(item, index) in breadInfo"
        :key="item.adcode"
        :style="{
          color:
            breadInfo.length === index + 1 || item.cityName === breadInfo[index + 1].cityName
              ? cssVars['--z-bread-text-active-color']
              : cssVars['--z-bread-text-color']
        }"
      >
        <span
          :style="{
            cursor:
              index !== breadInfo.length - 1 && item.cityName !== breadInfo[index + 1].cityName
                ? 'pointer'
                : ''
          }"
          @click="cityClick(index)"
        >
          {{ item.cityName }}
        </span>
        <span style="margin: 0 8px">{{
          index < 2 && breadInfo.length !== index + 1 ? '/' : ''
        }}</span>
      </span>
    </div>
    <div ref="basicMapRef" class="basic_map" :class="{ hidden_class: !datas.length }"></div>
    <div
      v-if="!datas.length"
      style="width: 100%; height: 100%; display: flex; align-items: center; justify-content: center"
    >
      暂无数据
      <!-- <nodata title="暂无数据"></nodata> -->
      <!-- <img style="width: 200px; margin: 300px auto" src="~/assets/images/common/empty_data.png" alt="" /> -->
    </div>
  </div>
</template>

<script setup lang="ts">
/**
 * 基本热力图
 * 其他功能请处理好数据后在传入options
 * 需要指定进入具体城市，可传入标准城市名及其上级
 */
import * as echarts from 'echarts'
import merge from 'deepmerge'
import adcodeJson from './adcode.json'
import worldJson from './world.json'
import { zhName, countryCenter } from './countryMap'
import AMapLoader from '@amap/amap-jsapi-loader'
// import nodata from '../nodata.vue'

const cssVars = ref({
  '--z-bread-text-color': '#666666',
  '--z-bread-text-active-color': '#999999'
})

type Item = {
  name: string
  value: string | number
  [key: string]: any
}

interface Props {
  unit?: string
  province?: string
  city?: string
  isWorld?: boolean
  datas: Array<Item>
  options?: object
  maxLevel?: number // 限制下钻层级
}
interface BreadInfo {
  cityName: string
  adcode: number | string
}
const props = defineProps<Props>()
const emit = defineEmits<{
  (e: 'elementClick', params: any): void
}>()

const geoJson = ref<any>()
const myChart = shallowRef<any>() // 使用shallowRef降低开销
const basicMapRef = ref<any>()
const breadInfo = reactive<BreadInfo[]>([
  {
    cityName: '全国',
    adcode: 100000
  }
])
const basicOptions = {
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: 'shadow'
    }
  },
  visualMap: {
    type: 'continuous',
    min: 0,
    max: 0,
    left: '3%',
    bottom: '5%',
    calculable: false,
    seriesIndex: [0],
    inRange: {
      color: ['#E3F2FF', '#BADAFF', '#0667D9']
      // color: ['#BADAFF', '#0667D9']
    },
    textStyle: {
      color: '#405775'
    },
    text: [] as any
  },
  geo: {
    map: 'map',
    silent: true,
    roam: false,
    z: 0,
    zoom: 1.2,
    top: '18%',
    itemStyle: {
      normal: {
        areaColor: '#bacfed',
        shadowColor: '#aec6e2',
        shadowBlur: 0,
        shadowOffsetX: 5,
        shadowOffsetY: 8,
        borderWidth: 0
      },
      emphasis: {
        areaColor: '#2AB8FF',
        borderWidth: 0,
        color: 'green',
        label: {
          show: false
        }
      }
    },
    regions: [
      {
        name: '南海诸岛',
        itemStyle: {
          areaColor: '#9DC3FF'
        },
        label: {
          show: false // 隐藏文字
        }
      }
    ]
  },
  series: [
    {
      type: 'map',
      map: 'map',
      roam: false,
      zoom: 1.2,
      top: '18%',
      nameMap: null as any,
      tooltip: {
        trigger: 'item',
        formatter: (p: any) => {
          let val = p.value
          if (p.name == '南海诸岛') return
          if (window.isNaN(val)) {
            val = 0
          }
          return (
            p.name +
            '&nbsp;&nbsp;&nbsp;' +
            (Number.isInteger(val) ? val : val.toFixed(2)) +
            (props.unit || '')
          )
        }
      },
      label: {
        show: false,
        color: '#000000',
        formatter: (p: any) => {
          switch (p.name) {
            case '内蒙古自治区':
              return '内蒙古'
            case '广西壮族自治区':
              return '广西'
            case '新疆维吾尔自治区':
              return '新疆'
            case '宁夏回族自治区':
              return '宁夏'
            case '西藏自治区':
              return '西藏'
            case '香港特别行政区':
              return '香港'
            case '澳门特别行政区':
              return '澳门'
            default:
              return p.name
          }
        }
      },
      itemStyle: {
        areaColor: '#bacfed',
        borderColor: '#A6C5ED',
        borderWidth: 0.5
      },
      emphasis: {
        label: {
          show: false
        }
      },
      data: [] as any
    }
  ]
}

const maxLevel = computed<number>(() => {
  return props.maxLevel ? props.maxLevel : 3
})

async function createMap(adcode: number | string) {
  new Promise(() => {
    return AMapLoader.load({
      key: '60fdb942e15dfeefff0d5595c58a8de3', // 申请好的Web端开发者Key，首次调用 load 时必填
      version: '2.0', // 指定要加载的 JSAPI 的版本，缺省时默认为 1.4.15
      // 需要使用的的插件列表，如比例尺'AMap.Scale'等
      plugins: [
        'AMap.DistrictLayer',
        'AMap.HeatMap',
        'Map3D',
        'AMap.Marker',
        'AMap.Geocoder',
        'AMap.DistrictSearch'
      ],
      AMapUI: {
        // 是否加载 AMapUI，缺省不加载
        version: '1.1', // AMapUI 版本
        plugins: ['overlay/SimpleMarker'] // 需要加载的 AMapUI ui插件
      },
      Loca: {
        // 是否加载 Loca， 缺省不加载
        version: '2.0.0' // Loca 版本
      }
    }).then(async (AMap: any) => {
      window.AMap = AMap
      init(adcode)
    })
    // .catch((err: any) => {
    //   console.log(err, 'err')
    // })
  })
}

// 初始化地图资源
function init(adcode: number | string) {
  getGeoJson(adcode).then((res: any) => {
    geoJson.value = res
    getMapData()
  })
}

// 获取区域数据
async function getGeoJson(adcode: number | string, childAdcode = '') {
  return new Promise((resolve, reject) => {
    function insideFun(adcode: string | number, childAdcode: string | number) {
      window.AMapUI.loadUI(['geo/DistrictExplorer'], (DistrictExplorer: any) => {
        var districtExplorer = new DistrictExplorer()
        districtExplorer.loadAreaNode(adcode, function (error: any, areaNode: any) {
          if (error) {
            reject(error)
            return
          }
          let Json = areaNode.getSubFeatures()

          if (Json.length === 0) {
            let parent = areaNode._data.geoData.parent.properties.acroutes
            insideFun(parent[parent.length - 1], adcode)
            return
          }

          if (childAdcode) {
            Json = Json.filter((item: any) => {
              return item.properties.adcode == childAdcode
            })
          }
          let mapJson = {
            features: Json
          }
          resolve(mapJson)
        })
      })
    }
    insideFun(adcode, childAdcode)
  })
}

// 地图点击事件
function echartsMapClick(params: any) {
  if (breadInfo.length >= maxLevel.value) return
  if (!params.data) {
    return
  } else {
    //如果当前是最后一级，那就直接return
    if (breadInfo[breadInfo.length - 1].adcode == params.data.adcode) {
      return
    }
    let data = params.data
    breadInfo.push({
      cityName: data.name,
      adcode: data.adcode
    })
    // 直辖市做特殊处理
    const specialCity = ['北京市', '上海市', '天津市', '重庆市']
    if (specialCity.includes(data.name)) {
      breadInfo.push({
        cityName: data.name,
        adcode: data.adcode
      })
    }
    init(data.adcode)
  }
  emit('elementClick', { ...params, breadData: breadInfo.slice(1) })
}

// 生成地图
function initChart(data: any) {
  const mapType = breadInfo.length === 1 && !props.isWorld ? 'china' : 'map'
  echarts.registerMap(mapType, props.isWorld ? worldJson : geoJson.value)
  !myChart.value && (myChart.value = echarts.init(basicMapRef.value))
  // myChart.value.showLoading()

  /** 合并配置 */
  const combineMerge = (target: any, source: any, options: any) => {
    const destination = target.slice()
    source.forEach((item: number, index: number) => {
      if (typeof destination[index] === 'undefined') {
        destination[index] = options.cloneUnlessOtherwiseSpecified(item, options)
      } else if (options.isMergeableObject(item)) {
        destination[index] = merge(target[index], item, options)
      } else if (target.indexOf(item) === -1) {
        destination.push(item)
      }
    })
    return destination
  }
  const arr = merge([basicOptions], [props.options as any], { arrayMerge: combineMerge }) as any
  const mergeoOptions = arr[0]

  mergeoOptions.series[0].data = data
  mergeoOptions.series[0].map = mapType
  mergeoOptions.geo.map = mapType

  if (props.isWorld) {
    mergeoOptions.series[0].nameMap = zhName
  } else {
    mergeoOptions.series[0].nameMap = null
  }
  myChart.value.setOption(mergeoOptions, true)
  setTimeout(() => {
    myChart.value.setOption(mergeoOptions)
    // myChart.value.hideLoading()
  }, 0)
  //点击前解绑，防止点击事件触发多次
  myChart.value.off('click')
  myChart.value.on('click', echartsMapClick)
}

// 获取数据
function getMapData() {
  let mapData: any = []

  let curGeoson = geoJson.value
  if (props.isWorld) {
    curGeoson = worldJson
  }

  if (!curGeoson || !props.datas.length) {
    myChart.value = null
    return
  }

  curGeoson.features.forEach((item: any) => {
    // let value = Math.random() * 3000
    /** 全球地图转换名字 */
    if (props.isWorld) {
      const chinaName = (zhName as any)[item.properties.name]
      const cur = props.datas.find((k: any) => chinaName === k.name)
      mapData.push({
        name: chinaName,
        value: cur?.value || 0,
        adcode: item.properties.adcode
      })
    } else {
      const cur = props.datas.find((k: any) => item.properties.name === k.name)
      mapData.push({
        name: item.properties.name,
        value: cur?.value || 0,
        adcode: item.properties.adcode
      })
    }
  })

  mapData = mapData.sort((a: any, b: any) => {
    return b.value - a.value
  })

  // 处理数据
  basicOptions.visualMap.max = mapData[0].value
  basicOptions.visualMap.text = [
    `${mapData[0].value}${props.unit || ''}`,
    `${mapData[mapData.length - 1].value}${props.unit || ''}`
  ]
  nextTick(() => {
    initChart(mapData)
  })
}

function updateChart() {
  if (!props.datas.length) return
  getMapData()
}

function cityClick(index: number) {
  if (index === breadInfo.length - 1) return
  if (index === 1 && breadInfo[1].cityName === breadInfo[2].cityName) return
  init(breadInfo[index].adcode)
  breadInfo.splice(index + 1)
  emit('elementClick', { seriesType: 'map', breadData: breadInfo.slice(1) })
}

onMounted(() => {
  // 具体城市自动生成面包屑
  if (props?.city) {
    ;[props.province, props.city].forEach((k: any) => {
      breadInfo.push({
        cityName: k,
        adcode: adcodeJson.Sheet1.find((e: any) => e.name === k)?.adcode as any
      })
    })
  }
  if (!window?.AMapUI) {
    createMap(breadInfo[breadInfo.length - 1].adcode)
    return
  }
  init(breadInfo[breadInfo.length - 1].adcode)
})

onUnmounted(() => {
  myChart.value && myChart.value.dispose()
})

watch(
  () => props.datas,
  () => updateChart(),
  { deep: true }
)
</script>

<style lang="less" scoped>
.basic_map_wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  .bread {
    position: absolute;
    left: 0;
    top: 16px;
    z-index: 99;
  }

  .basic_map {
    width: 100%;
    height: 100%;
  }
}
</style>
